package analyticsServer.dataLayer;

import java.util.Calendar;
import java.util.Hashtable;
import java.util.Vector;
import java.util.Enumeration;

import common.rmi.ClientReference;



public class DataLayer {
	
	private static final String[] eventTypes={"AUCTION_STARTED","AUCTION_ENDED","USER_LOGIN",
		"USER_LOGOUT","USER_DISCONNECTED","BID_PLACED","BID_OVERBID","BID_WON","USER_SESSIONTIME_MIN",
		"USER_SESSIONTIME_MAX","USER_SESSIONTIME_AVG", "BID_PRICE_MAX", "BID_COUNT_PER_MINUTE", 
		"AUCTION_TIME_AVG","AUCTION_SUCCESS_RATIO"};
	private static boolean exists=false;
	private static Hashtable<String, Vector<ClientReference>> subscriptions;
	private static Hashtable<String, Subscription> subscriptionIDs=new Hashtable<String, Subscription>();
	private static Hashtable<String, TimeInterval> auctionTimes=new Hashtable<String, TimeInterval>();
	private static Hashtable<String, TimeInterval> sessionTimes=new Hashtable<String, TimeInterval>();
	
	private static Double auctionCount=0d;
	private static double wonBidCount=0d;
	private static Double bidCount=0d;
	private static Boolean firstBid=true;
	private static Long firstBidTime;
	private static double bidPriceMax=0d;
	private static double userSessionMax=0d;
	private static double userSessionMin=0d;
	
	public DataLayer() {
		
	}
	
	public static Vector<ClientReference> getSubscriptions(String eventType){
		if(exists) return subscriptions.get(eventType);
		else return null;
	}
	public static Subscription getSubscription(String subscriptionID){
		return subscriptionIDs.get(subscriptionID);
	}
	public static void registerSubscription(String subscriptionID,Subscription subscription ){
		synchronized (subscriptionIDs) {
			subscriptionIDs.put(subscriptionID,subscription);
		}
		
		
	}
	public static void cancelSubscription(Subscription subscription ){
		synchronized(subscriptionIDs){
			subscriptionIDs.remove(subscription);
		}
	}
	public static void removeSubscriptionsOf(ClientReference client){
		
		synchronized(subscriptionIDs){
			Enumeration<String> e=subscriptionIDs.keys();

			while(e.hasMoreElements()){
				Subscription s=subscriptionIDs.get(e.nextElement());
				if(s.getClient().equals(client)){
					s.deactivate();
					subscriptionIDs.remove(s);
				}
			}
		}
		
	}
	public static void addSubscription(String eventType,Subscription subscription){
		synchronized(subscriptions) {
			if(subscriptions.get(eventType).contains(subscription.getClient())!=true)subscriptions.get(eventType).add(subscription.getClient());
		}
	}
	
	public static void removeSubscription(String eventType,Subscription subscription){
		synchronized (subscriptions) {
			subscriptions.get(eventType).remove(subscription.getClient());	
		}
	}
	
	public static void auctionBegins(long auctionID, long timestamp){
		synchronized(auctionTimes){
			auctionTimes.put(String.valueOf(auctionID), new TimeInterval(timestamp));
		}
	}
	
	public static void auctionEnds(long auctionID, long timestamp){
		synchronized (auctionTimes) {
			auctionTimes.get(String.valueOf(auctionID)).setEnd(timestamp);

			increaseFinishedAuctionCount();
			
		}
	}
	
	public static void userLoggedIn(String userName, long timestamp){
		synchronized(sessionTimes){
			sessionTimes.put(userName, new TimeInterval(timestamp));
		}
	}
	
	public static void userLoggedOut(String userName, long timestamp){
		synchronized(sessionTimes){
			sessionTimes.get(userName).setEnd(timestamp);
		}
		
	}

	public static void bidPlaced(double price, long timestamp){
		if(firstBid){
			firstBidPlaced(timestamp);
		}
		synchronized(bidCount){
			bidCount++;
		}
		
		if(price>bidPriceMax){
			bidPriceMax=price;
		}
	}
	
	private static synchronized void firstBidPlaced(long timestamp){
		firstBidTime=timestamp;
		firstBid=false;
	}
	
	public static synchronized void  increaseFinishedAuctionCount(){
		auctionCount++;
	}
	
	public static synchronized void increaseWonBidCount(){
		wonBidCount++;
	}
	
	public static double getMaxBidPrice(){
		return bidPriceMax;
	}
	
	public static double getBidCount(){
		return bidCount;
	}
	
	public static long getFirstBidTime(){
		return firstBidTime;
	}
	
	public static double getTotalAuctionDurations(){
		Enumeration<String> e=auctionTimes.keys();
		double total=0d;
		
		while(e.hasMoreElements()){
			TimeInterval auctionTiming=auctionTimes.get(e.nextElement());
			if(auctionTiming.getEnd()==-1l){
				total+=(double)(Calendar.getInstance().getTimeInMillis()-auctionTiming.getBegin());	
			}else total+=(double)(auctionTiming.getEnd()-auctionTiming.getBegin());
		}
		return total;
	}
	
	public static double getTotalSessionDurations(){
		Enumeration<String> e=sessionTimes.keys();
		double total=0d;
		long duration=0l;
		
		while(e.hasMoreElements()){
			TimeInterval sessionTiming=sessionTimes.get(e.nextElement());
			if(sessionTiming.getEnd()==-1l){
				duration=(Calendar.getInstance().getTimeInMillis()-sessionTiming.getBegin());	
			}else {
				duration=(sessionTiming.getEnd()-sessionTiming.getBegin());
			}
			if(duration<userSessionMin) userSessionMin=(double)duration;
			if(duration>userSessionMax) userSessionMax=(double)duration;
			total+=(double)duration;
		}
		return total;
	}
	
	public static double getMaxSessionDuration(){
		return userSessionMax;
	}
	
	public static double getMinSessionDuration(){
		return userSessionMin;
	}
	public static double getTotalSessionCount(){
		return sessionTimes.size();
	}
	public static double getTotalAuctionCount(){
		return auctionTimes.size();
	}
	
	public static double getFinishedAuctionCount(){
		return auctionCount;
	}
	
	public static double getWonBidCount(){
		return wonBidCount;
	}
	
	public static String[] getEventTypes(){
		return eventTypes;
	}
	
	public static synchronized void setKeys(){
		subscriptions=new Hashtable<String, Vector<ClientReference>>();
		
		for(int i=0;i<eventTypes.length;i++){
			subscriptions.put(eventTypes[i], new Vector<ClientReference>());	
		}
		exists=true;
	}
	
	public static synchronized void reset(){
		if(exists) exists=false;
	}
	
}
